//
//  BeansManager.m
//  SchemaToClass
//
//  Created by Chenly on 14-1-20.
//  Copyright (c) 2014年 Chenly. All rights reserved.
//

#import "BeansManager.h"
#import "Bean.h"

@implementation BeansManager
{
    NSMutableString *stringBufferImportH;
    NSMutableString *stringBufferImportM;
    
    NSMutableString *stringBufferClassH;
    
    NSMutableString *stringBufferContentH;
    NSMutableString *stringBufferContentM;
    NSMutableString *stringBufferInnerH;
    NSMutableString *stringBufferInnerM;
}

- (void)writeBeans:(NSArray *)beans externClasses:(NSArray *)externClasses importFiles:(NSArray *)importFiles toDirectory:(NSString *)directory fileName:(NSString *)fileName
{
    stringBufferImportH = [NSMutableString stringWithString:@"#import <Foundation/Foundation.h>\n#import \"Bean.h\"\n"];
    stringBufferImportM = [NSMutableString stringWithFormat:@"#import \"%@.h\"\n\n", fileName];
    
    stringBufferClassH = [[NSMutableString alloc] init];
    
    stringBufferContentH = [[NSMutableString alloc] init];
    stringBufferContentM = [[NSMutableString alloc] init];
    
    stringBufferInnerH = [[NSMutableString alloc] init];
    stringBufferInnerM = [[NSMutableString alloc] init];
    
    for (NSString *externClass in externClasses) {
        
        [stringBufferClassH appendFormat:@"@class %@;\n", [externClass capitalizedString]];
    }
    //在.m中写入@import
    for (NSString *importFile in importFiles) {
        
        [stringBufferImportM appendFormat:@"#import \"%@.h\"\n", importFile];
    }
    [stringBufferImportM appendString:@"\n"];
    
    [self writeBeans:beans inner:NO];
    [stringBufferClassH appendString:@"\n"];
    
    [stringBufferImportH appendString:stringBufferClassH];
    [stringBufferImportH appendString:stringBufferContentH];
    
    if (stringBufferInnerH.length > 0) {
        
        [stringBufferImportH appendString:@"\n#pragma mark - 内部类\n"];
        [stringBufferImportH appendString:stringBufferInnerH];
    }
    
    [stringBufferImportM appendString:stringBufferContentM];
    
    if (stringBufferInnerM.length > 0) {
        
        [stringBufferImportM appendString:@"\n#pragma mark - 内部类\n"];
        [stringBufferImportM appendString:stringBufferInnerM];
    }
    
    
    NSString *filePath = [directory stringByAppendingPathComponent:[fileName stringByAppendingPathExtension:@"h"]];
    [stringBufferImportH writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
    
    filePath = [directory stringByAppendingPathComponent:[fileName stringByAppendingPathExtension:@"m"]];
    [stringBufferImportM writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}

- (void)writeBeans:(NSArray *)beans inner:(BOOL)inner
{
    for (Bean *bean in beans) {
        
        //在.h中写入@class
        [stringBufferClassH appendFormat:@"@class %@;\n", [bean.name capitalizedString]];
        
        NSMutableString *stringInterface;
        NSMutableString *stringImplement;
        [self writeBean:bean stringInterface:&stringInterface stringImplement:&stringImplement];
        
        if (inner) {
            
            [stringBufferInnerH appendString:stringInterface];
            [stringBufferInnerM appendString:stringImplement];
        }
        else
        {
            [stringBufferContentH appendString:stringInterface];
            [stringBufferContentM appendString:stringImplement];
        }
        
        if (bean.innerBeans.count != 0) {
            
            [self writeBeans:bean.innerBeans inner:YES];
        }
    }
}

- (void)writeBean:(Bean *)bean stringInterface:(NSMutableString **)stringInterface stringImplement:(NSMutableString **)stringImplement
{
    *stringInterface = [[NSMutableString alloc] init];
    *stringImplement = [[NSMutableString alloc] init];
    
    NSMutableArray *propertyStrings = [[NSMutableArray alloc] init];      //所有属性声明
    NSMutableArray *hasPropertyStrings = [[NSMutableArray alloc] init];   //所有属性的has属性声明
    NSMutableArray *setMethodStrings = [[NSMutableArray alloc] init];     //所有.m中set方法的实现
    
    [*stringImplement appendFormat:@"@implementation %@\n", [bean.name capitalizedString]];
    
    [*stringInterface appendFormat:@"/*\n\t%@\n*/\n", bean.document];
    [*stringInterface appendFormat:@"@interface %@ : JSONObject\n", [bean.name capitalizedString]];
    
    NSEnumerator *keyEnumerator = bean.properties.keyEnumerator;
    NSString *key;
    while ((key = [keyEnumerator nextObject])) {
        
        NSString *propertyName = key;
        NSString *propertyType = bean.properties[key];
        
        NSString *propertyString;
        NSString *documentString = bean.documentations[key];
        if ([documentString rangeOfString:@"\n"].location == NSNotFound) {
            
            propertyString = [NSString stringWithFormat:@"%@%@;\t//%@\n", [self parsePropertyType:propertyType propertyName:propertyName hasHeader:YES], propertyName, documentString];
        }
        else
        {
            propertyString = [NSString stringWithFormat:@"/*\n%@\n*/\n%@%@;\n", [documentString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]], [self parsePropertyType:propertyType propertyName:propertyName hasHeader:YES], propertyName];
        }
        //对于名为id和class这种系统保留字的propertyName加"_"前缀
        NSString *additionalString = @"";
        if ([propertyName isEqualToString:@"_id"]) {
            
            propertyName = @"id";
            additionalString = @"_";
        }
        
        NSString *propertyNameUppercase = [propertyName stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[propertyName substringToIndex:1] uppercaseString]];
        
        NSString *hasPropertyString = [NSString stringWithFormat:@"@property (nonatomic, readonly) BOOL has%@;\n", propertyNameUppercase];

        NSMutableString *setMethodString = [NSMutableString stringWithFormat:@"- (void)set%@:(%@)%@%@\n{\n", propertyNameUppercase, [self parsePropertyType:propertyType propertyName:nil hasHeader:NO], additionalString, propertyName];

        if (!([propertyType isEqualToString:@"int"] || [propertyType isEqualToString:@"integer"] || [propertyType isEqualToString:@"decimal"] || [propertyType isEqualToString:@"boolean"])) {
            
            [setMethodString appendFormat:@"\tif (%@%@ == nil)\n\t\t_has%@ = NO;\n\telse\n\t", additionalString, propertyName, propertyNameUppercase];
        }
        [setMethodString appendFormat:@"\t_has%@ = YES;\n\t_%@%@ = %@%@;\n}\n", propertyNameUppercase, additionalString, propertyName, additionalString, propertyName];
        
        [propertyStrings addObject:hasPropertyString];
        [hasPropertyStrings addObject:propertyString];
        [setMethodStrings addObject:setMethodString];
    }
    
    for (NSString *str in propertyStrings) {
        
        [*stringInterface appendString:str];
    }
    for (NSString *str in hasPropertyStrings) {
        
        [*stringInterface appendString:str];
    }
    for (NSString *str in setMethodStrings) {
        
        [*stringImplement appendString:str];
    }
    
    //数组Property的getterAtIndex方法
    NSMutableString *returnTypeMethod = [NSMutableString stringWithString:@"- (NSString *)returnTypeOfArrayProperty:(NSString *)propertyName\n{\n"];
    keyEnumerator = bean.arrayPropertyTypes.keyEnumerator;
    while ((key = [keyEnumerator nextObject])) {
        
        NSString *propertyName = key;
        [*stringInterface appendFormat:@"- (%@)%@AtIndex:(NSInteger)index;\n", [self parsePropertyType:bean.arrayPropertyTypes[key] propertyName:nil hasHeader:NO], propertyName];
        [*stringImplement appendFormat:@"- (%@)%@AtIndex:(NSInteger)index\n{\n\treturn _%@[index];\n}\n", [self parsePropertyType:bean.arrayPropertyTypes[key] propertyName:nil hasHeader:NO], propertyName, propertyName];
        NSString *returnType = [self parsePropertyType:bean.arrayPropertyTypes[key] propertyName:nil hasHeader:NO];
        returnType = [returnType substringToIndex:returnType.length - 2];
        [returnTypeMethod appendFormat:@"\tif ([propertyName isEqualToString:@\"%@\"]) {\n\t\treturn @\"%@\";\n\t}\n", propertyName, returnType];
    }
    [returnTypeMethod appendString:@"\treturn nil;\n}\n"];
    [*stringImplement appendString:returnTypeMethod];
    [*stringInterface appendString:@"@end\n\n"];
    [*stringImplement appendString:@"@end\n\n"];
}

- (NSString *)parsePropertyType:(NSString *)propertyType propertyName:(NSString *)propertyName hasHeader:(BOOL)hasHeader
{
    if (hasHeader) {
        
        NSString *getterString = @"";
        NSString *setterString = @"";
        NSString *addtionalString = @"";
        if (propertyName && ([propertyName rangeOfString:@"init"].location == 0 || [propertyName rangeOfString:@"new"].location == 0)) {
            
            getterString = [NSString stringWithFormat:@", getter = get%@", [propertyName capitalizedString]];
        }
        if ([propertyName isEqualToString:@"_id"]) {
            
            getterString = @", getter = getId";
            setterString = @", setter = setId:";
        }
        
        addtionalString = [NSString stringWithFormat:@"%@%@", getterString, setterString];
        
        if ([propertyType isEqualToString:@"string"]) {
            
            return [NSString stringWithFormat:@"@property (nonatomic, strong%@) NSString *", addtionalString];
        }
        if ([propertyType isEqualToString:@"decimal"]) {
            
            return [NSString stringWithFormat:@"@property (nonatomic, assign%@) double ", addtionalString];;
        }
        if ([propertyType isEqualToString:@"integer"] || [propertyType isEqualToString:@"int"]) {
            
            return [NSString stringWithFormat:@"@property (nonatomic, assign%@) NSInteger ", addtionalString];;
        }
        if ([propertyType isEqualToString:@"boolean"]) {
            
            return [NSString stringWithFormat:@"@property (nonatomic, assign%@) BOOL ", addtionalString];;
        }
        if ([propertyType isEqualToString:@"array"]) {
            
            return [NSString stringWithFormat:@"@property (nonatomic, strong%@) NSArray *", addtionalString];;
        }
        if ([propertyType isEqualToString:@"anyType"]) {
            
            return [NSString stringWithFormat:@"@property (nonatomic, strong%@) JSONObject *", addtionalString];;
        }
        return [NSString stringWithFormat:@"@property (nonatomic, strong%@) %@ *", addtionalString, [propertyType capitalizedString]];
    }
    else
    {
        if ([propertyType isEqualToString:@"string"]) {
            
            return @"NSString *";
        }
        if ([propertyType isEqualToString:@"decimal"]) {
            
            return @"double";
        }
        if ([propertyType isEqualToString:@"integer"] || [propertyType isEqualToString:@"int"]) {
            
            return @"NSInteger";
        }
        if ([propertyType isEqualToString:@"boolean"]) {
            
            return @"BOOL";
        }
        if ([propertyType isEqualToString:@"array"]) {
            
            return @"NSArray *";
        }
        if ([propertyType isEqualToString:@"anyType"]) {
            
            return @"JSONObject *";
        }
        return [NSString stringWithFormat:@"%@ *", [propertyType capitalizedString]];
    }
}

@end
